package core.comunication;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;

import core.manager.TQueueManager;
import core.util.COREServiceRegistry;
import core.worker.Address;

/**
 * La classe MessageServer si occupa della messagistica e scambio delle informazioni. Rappresenta l'helper che richiama i thread di gestione della messagistica
 * In particolare istanzia 3 thread, uno in ascolto per la ricezione dei messaggi, uno relativo alla ricezione del file, uno relativo all'invio dei messaggi in uscita
 * Essa detiene la coda dei pacchetti condivisa tra il Thread UDPHandler  e il Thread UDP Listen. 
 * @see UDPHandler
 * @see UDPListen
 * @author Vincenzo Merlo, Scuderi Giovanni Luca, Paolo Giuffrida
 */
public class MessageServer {
	private static final Logger logger = COREServiceRegistry.getLogger(MessageServer.class.toString());
	private volatile static MessageServer instance;
	private static LinkedBlockingQueue<MSGTDEnqueue> messages;
	private static LinkedBlockingQueue<MSGRequestUpload> messagesUP;
	private static TQueueManager tq;
	private Address addr = null;

	private MessageServer() {
		messages  = new LinkedBlockingQueue<MSGTDEnqueue>();
		messagesUP = new LinkedBlockingQueue<MSGRequestUpload>();
		logger.debug("MessageServer");
	}

	public void start () {
		/**Server che riceve i paccjetti su port, in base al payload riempie i le code messages o messagesUP*/
		ExecutorService serviceMessages = Executors.newSingleThreadScheduledExecutor();  
		serviceMessages.execute(new UDPListen(addr.getPort())); 

		ExecutorService serviceFile = Executors.newSingleThreadScheduledExecutor();  //invia 
		serviceFile.execute(new FileServer(addr.getPort() + 1)); 

		ExecutorService serviceHandler = Executors.newSingleThreadScheduledExecutor(); //invia
		serviceHandler.execute(new UDPHandler(addr.getPort() + 1));
	}

	/**
	 * metodo per singleton
	 * @return istanza
	 */
	public static MessageServer getInstance() {
		if (instance == null) {
			synchronized (MessageServer.class) {
				if (instance == null)
					instance = new MessageServer();
			}
		} 

		return instance;
	}

	/**
	 * Setter del TQueueManager
	 * @param tq istanza del TQueueManager
	 */
	public void setTQ(TQueueManager tq) {
		MessageServer.tq = tq;
	}


	/**
	 * Getter del TQueueManager
	 * @return istanza del TQueueManager
	 */
	public static TQueueManager getTQ() {
		return MessageServer.tq;
	}

//	/**
//	 * Aggiunge un messaggio udp per il trasferimento
//	 * @param packet pacchetto UDP da aggiungere
//	 */
//	public static void addMessage(MSGTDEnqueue packet) {
//		//COREServiceRegistry.getLogger(TQueueManagerProxyP2P.class.toString()).trace("aggiungo " + new String(packet.getBuffer()));
//		messages.add(packet);
//	}

	public synchronized static BlockingQueue<MSGTDEnqueue> getMessages() {
		return messages;
	}

	public synchronized static void setMessages(LinkedBlockingQueue<MSGTDEnqueue> messages) {
		MessageServer.messages = messages;
	}

	public void setAddr(Address addr) {
		this.addr = addr;
	}

	public Address getAddr() {
		return addr;
	}

	public synchronized static BlockingQueue<MSGRequestUpload> getMessagesUP() {
		return messagesUP;
	}

	public synchronized static void setMessagesUP(LinkedBlockingQueue<MSGRequestUpload> messagesUP) {
		MessageServer.messagesUP = messagesUP;
	}



}